package src;

import javax.swing.*;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

public class FileOperations {
    // 获取系统剪贴板实例
    private static Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
    // 存储复制的文件路径
    private static Path copiedPath;

    /**
     * 复制文件或目录到剪贴板
     *
     * @param file 要复制的文件或目录
     */
    public static void copyFileOrDirectory(File file) {
        if (file != null && file.exists()) {
            // 设置要复制的文件路径
            copiedPath = Paths.get(file.getAbsolutePath());
            // 将文件路径放入剪贴板
            StringSelection selection = new StringSelection(copiedPath.toString());
            clipboard.setContents(selection, null);
            // 显示成功消息对话框
            JOptionPane.showMessageDialog(null, "Copied: " + file.getAbsolutePath(), "Success", JOptionPane.INFORMATION_MESSAGE);
        } else {
            // 显示错误消息对话框
            JOptionPane.showMessageDialog(null, "No valid file or directory selected.", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 从剪贴板粘贴文件或目录到指定的目标目录
     *
     * @param destinationDir 目标目录
     * @param fileListPanel 文件列表面板，用于更新文件列表
     */
    public static void pasteFileOrDirectory(File destinationDir, FileListPanel fileListPanel) {
        //检查剪贴板中是否有字符串类型的可用数据（即之前复制的文件路径）。
        //如果没有，则显示错误消息并返回。
        if (clipboard.isDataFlavorAvailable(DataFlavor.stringFlavor)) {
            try {
                // 从剪贴板获取数据
                String path = (String) clipboard.getData(DataFlavor.stringFlavor);
                File source = new File(path);
                if (source.exists()) {
                    File destination = new File(destinationDir, source.getName());
                    // 如果目标文件或目录已存在，提示用户是否覆盖
                    if (destination.exists()) {
                        int option = JOptionPane.showConfirmDialog(null,
                                "The file/directory '" + destination.getName() + "' already exists. Do you want to overwrite it?",
                                "File/Directory Exists", JOptionPane.YES_NO_CANCEL_OPTION);
                        if (option == JOptionPane.CANCEL_OPTION) return;
                        if (option == JOptionPane.NO_OPTION) {
                            // 生成一个新的文件名
                            destination = getUniqueFileName(destination);
                        }
                    }

                    // 根据源文件类型执行不同的复制操作
                    if (source.isDirectory()) {
                        copyDirectory(source, destination);
                    } else {
                        copyFile(source, destination);
                    }

                    // 显示成功消息对话框并更新文件列表
                    JOptionPane.showMessageDialog(null, "Pasted: " + source.getAbsolutePath() + " to " + destinationDir.getAbsolutePath(), "Success", JOptionPane.INFORMATION_MESSAGE);
                    fileListPanel.updateFileList(destinationDir);
                } else {
                    // 显示错误消息对话框
                    JOptionPane.showMessageDialog(null, "Source file or directory does not exist.", "Error", JOptionPane.ERROR_MESSAGE);
                }
            } catch (Exception ex) {
                // 显示错误消息对话框并打印堆栈跟踪
                JOptionPane.showMessageDialog(null, "Failed to paste: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        } else {
            // 显示错误消息对话框
            JOptionPane.showMessageDialog(null, "Nothing to paste.", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 生成唯一的文件名以避免冲突
     *
     * @param originalFile 原始文件
     * @return 新的唯一文件对象
     */
    private static File getUniqueFileName(File originalFile) {
        String baseName = originalFile.getName();
        String extension = "";
        int dotIndex = baseName.lastIndexOf('.');
        if (dotIndex > 0) {
            extension = baseName.substring(dotIndex);
            baseName = baseName.substring(0, dotIndex);
        }
        File parentDir = originalFile.getParentFile();
        for (int i = 1; ; i++) {
            String newName = baseName + " (" + i + ")" + extension;
            File newFile = new File(parentDir, newName);
            if (!newFile.exists()) {
                return newFile;
            }
        }
    }

    /**
     * 删除文件或目录
     *
     * @param file 要删除的文件或目录
     * @param fileListPanel 文件列表面板，用于更新文件列表
     */
    public static void deleteFileOrDirectory(File file, FileListPanel fileListPanel) {
        if (file != null && file.exists()) {
            if (deleteRecursively(file)) {
                // 显示成功消息对话框并更新文件列表
                JOptionPane.showMessageDialog(null, "Deleted: " + file.getAbsolutePath(), "Success", JOptionPane.INFORMATION_MESSAGE);
                fileListPanel.updateFileList(file.getParentFile());
            } else {
                // 显示错误消息对话框
                JOptionPane.showMessageDialog(null, "Failed to delete: " + file.getAbsolutePath(), "Error", JOptionPane.ERROR_MESSAGE);
            }
        } else {
            // 显示错误消息对话框
            JOptionPane.showMessageDialog(null, "No valid file or directory selected.", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }

    /**
     * 复制单个文件
     *
     * @param source 源文件
     * @param dest 目标文件
     * @throws IOException 如果发生I/O错误
     */
    private static void copyFile(File source, File dest) throws IOException {
        //try-with-resources 语句:
        //特点:
        //自动关闭资源: 在 try 块结束时，无论是否发生异常，所有在 try 括号中声明的资源都会自动关闭。
        //简化代码: 不需要显式调用 close() 方法，减少了样板代码。
        //支持多个资源: 可以在同一 try 语句中声明多个资源，中间用分号隔开。
        //适用范围:
        //适用于实现了 AutoCloseable 接口的类，如 FileInputStream、FileOutputStream、BufferedReader 等。
        try (FileInputStream fis = new FileInputStream(source);
             FileOutputStream fos = new FileOutputStream(dest)) {
            //创建一个大小为 1024 字节的缓冲区 buffer。
            //使用 fis.read(buffer) 从源文件中读取数据到缓冲区，并返回实际读取的字节数。
            //使用 fos.write(buffer, 0, length) 将缓冲区中的数据写入目标文件。
            //循环执行上述操作，直到读取到文件末尾（即 read 返回 -1）
            byte[] buffer = new byte[1024];
            int length;
            while ((length = fis.read(buffer)) > 0) {
                fos.write(buffer, 0, length);
            }
        }
    }

    /**
     * 复制整个目录及其内容
     *
     * @param source 源目录
     * @param dest 目标目录
     * @throws IOException 如果发生I/O错误
     */
    private static void copyDirectory(File source, File dest) throws IOException {
        if (!dest.exists()) {
            dest.mkdirs();
        }

        File[] files = source.listFiles();
        if (files != null) {
            for (File file : files) {
                File target = new File(dest, file.getName());
                if (file.isDirectory()) {
                    copyDirectory(file, target);
                } else {
                    copyFile(file, target);
                }
            }
        }
    }

    /**
     * 递归删除文件或目录
     *
     * @param file 要删除的文件或目录
     * @return 如果删除成功返回true，否则返回false
     */
    private static boolean deleteRecursively(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File f : files) {
                    if (!deleteRecursively(f)) {
                        return false;
                    }
                }
            }
        }
        return file.delete();
    }
}